#include "auditlogger.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include "AuditEntry.h"  // 添加头文件包含
#include <QJsonDocument>

// 实现新增的成员函数
QString AuditLogger::getDatabasePath() const
{
    return m_dbPath;
}

QString AuditLogger::getEncryptionPassword() const
{
    return m_encryptionPassword;
}

AuditLogger::AuditLogger(QObject *parent) : QObject(parent)
{
    // 生成唯一连接名（使用对象地址确保唯一性）
    m_connectionName = QString("audit_connection_%1").arg(reinterpret_cast<quintptr>(this), 0, 16);
}

AuditLogger::~AuditLogger()
{
    if (m_db.isOpen()) {
        // 显式清除所有关联查询（假设查询使用局部变量，此处通过关闭数据库隐式清除）
        m_db.close();
        // 确保无其他对象持有该连接引用后再移除
        QSqlDatabase::removeDatabase(m_connectionName);
    }
}

bool AuditLogger::initialize(const QString &dbPath, const QString &password)
{
    if (m_initialized) {
        qWarning() << "[Audit] 审计系统已初始化，无需重复操作";
        return true;
    }
    
    if(dbPath.isEmpty()) {
        qCritical() << "[Audit] 数据库路径不能为空";
        return false;
    }
    
    qDebug() << "[Audit] 正在初始化数据库:" << dbPath;
    
    m_dbPath = dbPath;
    m_db = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
    m_db.setDatabaseName(m_dbPath);

    if (!m_db.open()) {
        qCritical() << "[Audit] 打开数据库失败:" << m_db.lastError().text();
        return false;
    }

    if (!password.isEmpty()) {
        qDebug() << "[Audit] 正在应用数据库加密";
        m_encryptionPassword = password;
        QSqlQuery query(m_db);
        query.prepare("SELECT hex(sqlcipher_export())");
        query.exec("PRAGMA key='" + password + "'");
        query.exec("PRAGMA kdf_iter=64000");
        query.exec("PRAGMA cipher_page_size=4096");
    }

    bool result = createTables();
    if (result) {
        m_initialized = true;
    }
    return result;
}


bool AuditLogger::createTables() noexcept
{
    QSqlQuery query(m_db);
    
    // 检查表是否存在，不存在则创建
    if (!query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='audit_log'")) {
        qCritical() << "Failed to check audit_log table:" << query.lastError().text();
        return false;
    }
    
    if (!query.next()) {
        qDebug() << "audit_log table does not exist, creating now...";
        // 创建审计日志表
        if (!query.exec(R"(
            CREATE TABLE audit_log (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp DATETIME NOT NULL,
                user_id TEXT NOT NULL,
                action TEXT NOT NULL,
                table_name TEXT,
                record_id TEXT,
                old_value TEXT,
                new_value TEXT,
                description TEXT,
                checksum TEXT NOT NULL
            )
        )")) {
            qCritical() << "Failed to create audit_log table:" << query.lastError().text();
            return false;
        }
        // 创建索引
        query.exec("CREATE INDEX idx_audit_log_timestamp ON audit_log(timestamp)");
        query.exec("CREATE INDEX idx_audit_log_user ON audit_log(user_id)");
        query.exec("CREATE INDEX idx_audit_log_action ON audit_log(action)");
        query.exec("CREATE INDEX idx_audit_log_table ON audit_log(table_name)");
    }

    // 检查索引是否存在
    QStringList requiredIndexes = {
        "idx_audit_log_timestamp",
        "idx_audit_log_user",
        "idx_audit_log_action",
        "idx_audit_log_table"
    };
    
    for (const auto &indexName : requiredIndexes) {
        if (!query.exec(QString("SELECT name FROM sqlite_master WHERE type='index' AND name='%1'").arg(indexName))) {
            qWarning() << "Failed to check index" << indexName << ":" << query.lastError().text();
            continue;
        }
        if (!query.next()) {
            qWarning() << "Index" << indexName << "does not exist";
        }
    }

    return true;
}

bool AuditLogger::logEvent(const AuditLogger::AuditRecord &record)
{
    if (!m_db.isOpen()) {
        qWarning() << "Database is not open";
        return false;
    }

    QSqlQuery query(m_db);
    query.prepare(R"(
        INSERT INTO audit_log (
            timestamp, user_id, action, table_name, 
            record_id, old_value, new_value, description, checksum
        ) VALUES (
            :timestamp, :user_id, :action, :table_name, 
            :record_id, :old_value, :new_value, :description, :checksum
        )
    )");

    // 计算校验和以确保数据完整性
    QString dataToHash = QString("%1%2%3%4%5%6%7")
                            .arg(record.timestamp.toString(Qt::ISODate))
                            .arg(record.userId)
                            .arg(actionToString(record.action))
                            .arg(record.tableName)
                            .arg(record.recordId)
                            .arg(record.oldValue)
                            .arg(record.newValue);

    // 简单校验和实现，实际项目中应使用更安全的哈希算法
    QString checksum = QString::number(qHash(dataToHash));

    query.bindValue(":timestamp", record.timestamp);
    query.bindValue(":user_id", record.userId);
    query.bindValue(":action", actionToString(record.action));
    query.bindValue(":table_name", record.tableName);
    query.bindValue(":record_id", record.recordId);
    query.bindValue(":old_value", record.oldValue);
    query.bindValue(":new_value", record.newValue);
    query.bindValue(":description", record.description);
    query.bindValue(":checksum", checksum);

    if (!query.exec()) {
        qCritical() << "Failed to log audit event:" << query.lastError().text();
        return false;
    }

    return true;
}

QVector<AuditLogger::AuditRecord> AuditLogger::queryEvents(const QString &userId, 
                                             const QDateTime &from, 
                                             const QDateTime &to,
                                             AuditLogger::ActionType action) const
{
    QVector<AuditRecord> records;
    if (!m_db.isOpen()) {
        return records;
    }

    QSqlQuery query(m_db);
    QString sql = "SELECT * FROM audit_log WHERE 1=1";
    
    if (!userId.isEmpty()) {
        sql += " AND user_id = :user_id";
    }
    if (from.isValid()) {
        sql += " AND timestamp >= :from";
    }
    if (to.isValid()) {
        sql += " AND timestamp <= :to";
    }
    if (action != AuditLogger::ActionType::System) {
        sql += " AND action = :action";
    }

    sql += " ORDER BY timestamp DESC";

    query.prepare(sql);

    if (!userId.isEmpty()) {
        query.bindValue(":user_id", userId);
    }
    if (from.isValid()) {
        query.bindValue(":from", from);
    }
    if (to.isValid()) {
        query.bindValue(":to", to);
    }
    if (action != AuditLogger::ActionType::System) {
        query.bindValue(":action", actionToString(action));
    }

    if (!query.exec()) {
        qWarning() << "Failed to query audit events:" << query.lastError().text();
        return records;
    }

    while (query.next()) {
        AuditRecord record;
        record.timestamp = query.value("timestamp").toDateTime();
        record.userId = query.value("user_id").toString();
        
        QString actionStr = query.value("action").toString();
        if (actionStr == "Create") record.action = AuditLogger::ActionType::Create;
        else if (actionStr == "Read") record.action = AuditLogger::ActionType::Read;
        else if (actionStr == "Update") record.action = AuditLogger::ActionType::Update;
        else if (actionStr == "Delete") record.action = AuditLogger::ActionType::Delete;
        else if (actionStr == "Login") record.action = AuditLogger::ActionType::Login;
        else if (actionStr == "Logout") record.action = AuditLogger::ActionType::Logout;
        else record.action = AuditLogger::ActionType::System;

        record.tableName = query.value("table_name").toString();
        record.recordId = query.value("record_id").toString();
        record.oldValue = query.value("old_value").toString();
        record.newValue = query.value("new_value").toString();
        record.description = query.value("description").toString();

        records.append(record);
    }

    return records;
    return records;
}

QList<AuditLogger::AuditRecord> AuditLogger::getAuditRecords(const QDateTime &from,
                                                            const QDateTime &to,
                                                            const QString &userId,
                                                            const QString &action) const
{
    QList<AuditRecord> records;
    if (!m_db.isOpen()) {
        qWarning() << "[Audit] Database is not open for getAuditRecords";
        return records;
    }

    QSqlQuery query(m_db);
    QString sql = "SELECT * FROM audit_log WHERE 1=1";
    
    if (!userId.isEmpty()) {
        sql += " AND user_id = :user_id";
    }
    if (from.isValid()) {
        sql += " AND timestamp >= :from";
    }
    if (to.isValid()) {
        sql += " AND timestamp <= :to";
    }
    if (!action.isEmpty()) {
        sql += " AND action = :action";
    }

    sql += " ORDER BY timestamp DESC LIMIT 100"; // Limit to prevent too many records

    query.prepare(sql);

    if (!userId.isEmpty()) {
        query.bindValue(":user_id", userId);
    }
    if (from.isValid()) {
        query.bindValue(":from", from);
    }
    if (to.isValid()) {
        query.bindValue(":to", to);
    }
    if (!action.isEmpty()) {
        query.bindValue(":action", action);
    }

    if (!query.exec()) {
        qWarning() << "[Audit] Failed to query audit records:" << query.lastError().text();
        return records;
    }

    while (query.next()) {
        AuditRecord record;
        record.timestamp = query.value("timestamp").toDateTime();
        record.userId = query.value("user_id").toString();
        
        QString actionStr = query.value("action").toString();
        if (actionStr == "Create") record.action = AuditLogger::ActionType::Create;
        else if (actionStr == "Read") record.action = AuditLogger::ActionType::Read;
        else if (actionStr == "Update") record.action = AuditLogger::ActionType::Update;
        else if (actionStr == "Delete") record.action = AuditLogger::ActionType::Delete;
        else if (actionStr == "Login") record.action = AuditLogger::ActionType::Login;
        else if (actionStr == "Logout") record.action = AuditLogger::ActionType::Logout;
        else record.action = AuditLogger::ActionType::System;

        record.tableName = query.value("table_name").toString();
        record.recordId = query.value("record_id").toString();
        record.oldValue = query.value("old_value").toString();
        record.newValue = query.value("new_value").toString();
        record.description = query.value("description").toString();

        records.append(record);
    }

    qDebug() << "[Audit] Retrieved" << records.size() << "audit records from database";
    return records;
}

QString AuditLogger::actionToString(AuditLogger::ActionType action)
{
    switch (action) {
    case AuditLogger::ActionType::Create: return "Create";
    case AuditLogger::ActionType::Read: return "Read";
    case AuditLogger::ActionType::Update: return "Update";
    case AuditLogger::ActionType::Delete: return "Delete";
    case AuditLogger::ActionType::Login: return "Login";
    case AuditLogger::ActionType::Logout: return "Logout";
    case AuditLogger::ActionType::System: return "System";
    default: return "System";
    }
}

void AuditLogger::logEntry(const AuditEntry& entry) {
    if (!m_initialized) {
        qCritical() << "[Audit] 审计系统未初始化，请先调用initialize()方法";
        return;
    }
    qDebug() << "[Audit] 正在记录审计条目，user:" << entry.user << "初始化状态:" << m_db.isOpen() << " 数据库路径:" << m_dbPath;  // 新增user字段日志
    
    if(entry.user.isEmpty()) {  // 新增空值检查
        qCritical() << "[Audit] 审计条目user字段为空，无法满足数据库非空约束";
        return;
    }
    
    if(!m_db.isOpen()) {
        qCritical() << "[Audit] 数据库未连接! 可能原因:";
        qCritical() << "1. 未调用initialize()方法";
        qCritical() << "2. 数据库路径不正确:" << m_dbPath;
        qCritical() << "3. 加密配置不匹配";
        return;
    }
    AuditRecord record{
        entry.timestamp,
        entry.user,  // 此处依赖entry.user的有效性
        static_cast<ActionType>(actionStringToEnum(entry.action.toUpper())),
        entry.table,
        entry.recordId,
        QString(QJsonDocument::fromVariant(entry.oldValues).toJson()),
        QString(QJsonDocument::fromVariant(entry.newValues).toJson()),
        entry.description
    };
    
    logEvent(record);
}

// 修正枚举转换方法
int AuditLogger::actionStringToEnum(const QString& action) {
    if (action.toUpper() == "CREATE") return Create;
    if (action.toUpper() == "UPDATE") return Update;
    if (action.toUpper() == "DELETE") return Delete;
    if (action.toUpper() == "LOGIN") return Login;
    if (action.toUpper() == "LOGOUT") return Logout;
    return System;
}

void AuditLogger::logAction(AuditLogger::ActionType action, const QString &details) {
    AuditLogger::AuditRecord record;
    record.timestamp = QDateTime::currentDateTime();
    record.action = action;
    record.description = details;
    logEvent(record);
}